home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / tde40.zip / ed.c < prev    next >
C/C++ Source or Header  |  1994-06-05  |  71KB  |  2,328 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - main editor module
  10.  * Purpose: This file contains the main editor module, and a number of the
  11.  *           smaller miscellaneous editing commands.
  12.  *          It also contains the code for dispatching commands.
  13.  * File:    ed.c
  14.  * Author:  Douglas Thomson
  15.  * System:  this file is intended to be system-independent
  16.  * Date:    October 1, 1989
  17.  * I/O:     file being edited
  18.  *          files read or written
  19.  *          user commands and prompts
  20.  * Notes:   see the file "dte.doc" for general program documentation
  21.  */
  22. /*********************  end of original comments   ********************/
  23.  
  24. /*
  25.  * The basic editor routines have been EXTENSIVELY rewritten.  I have added
  26.  * support for lines longer than 80 columns and I have added line number
  27.  * support.  I like to know the real line number that editor functions are
  28.  * working on and I like to know the total number of lines in a file.
  29.  *
  30.  * I rewrote the big series of ifs in the dispatch subroutine.  It is now
  31.  * an array of pointers to functions.  We know what function to call as soon
  32.  * as a key is pressed.  It is also makes it easier to implement a configuration
  33.  * utility and macros.
  34.  *
  35.  * I added a few functions that I use quite often and I deleted a few that I
  36.  * rarely use.  Added are Split Line, Join Line, and Duplicate Line.  Deleted
  37.  * are Goto Marker 0-9 (others?).
  38.  *
  39.  * ************ In TDE 1.3, I put Goto Marker 0-9 back in.  ***************
  40.  *
  41.  * I felt that the insert routine should be separated into two routines.  One
  42.  * for inserting the various combinations of newlines and one for inserting
  43.  * ASCII and extended ASCII characters.
  44.  *
  45.  * One of Doug's design considerations was keeping screen updates to a minimum.
  46.  * I have expanded upon that idea and added support for updating windows
  47.  * LOCALly, GLOBALly, or NOT_LOCALly.  For example, scrolling in one window
  48.  * does not affect the text in another window - LOCAL update.  Adding, deleting,
  49.  * or modifying text in one window may affect text in other windows - GLOBAL
  50.  * update.  Sometimes, updates to the current window are handled in the task
  51.  * routines so updates to other windows are done NOT_LOCALly.
  52.  *
  53.  * In version 2.2, the big text buffer scheme was replaced by a double
  54.  *  linked list.
  55.  *
  56.  * New editor name:  TDE, the Thomson-Davis Editor.
  57.  * Author:           Frank Davis
  58.  * Date:             June 5, 1991, version 1.0
  59.  * Date:             July 29, 1991, version 1.1
  60.  * Date:             October 5, 1991, version 1.2
  61.  * Date:             January 20, 1992, version 1.3
  62.  * Date:             February 17, 1992, version 1.4
  63.  * Date:             April 1, 1992, version 1.5
  64.  * Date:             June 5, 1992, version 2.0
  65.  * Date:             October 31, 1992, version 2.1
  66.  * Date:             April 1, 1993, version 2.2
  67.  * Date:             June 5, 1993, version 3.0
  68.  * Date:             August 29, 1993, version 3.1
  69.  * Date:             November 13, 1993, version 3.2
  70.  * Date:             June 5, 1994, version 4.0
  71.  *
  72.  * This modification of Douglas Thomson's code is released into the
  73.  * public domain, Frank Davis.   You may distribute it freely.
  74.  */
  75.  
  76. #include "tdestr.h"     /* typedefs for global variables */
  77. #include "define.h"     /* editor function defs */
  78. #include "tdefunc.h"    /* prototypes for all functions in tde */
  79. #include "global.h"     /* global variables */
  80. #include "prompts.h"    /* prompt assignments */
  81. #include "default.h"    /* default function key assignments */
  82.  
  83.  
  84. /*
  85.  * Name:    insert_newline
  86.  * Purpose: insert a newline
  87.  * Date:    June 5, 1991
  88.  * Passed:  window:  pointer to current window
  89.  * Notes:   There a several ways to insert a line into a file:  1) pressing
  90.  *          a key, 2) word wrap, 3) any others?
  91.  *          When doing word wrap or format paragraph, don't show any changes.
  92.  *            Wait until the function finishes then show all changes at once.
  93.  */
  94. int  insert_newline( TDE_WIN *window )
  95. {
  96. char *source;           /* source for block move to make room for c */
  97. char *dest;             /* destination for block move */
  98. int  len;               /* length of current line */
  99. int  split_len;
  100. int  add;               /* characters to be added (usually 1 in insert mode) */
  101. int  rcol;
  102. int  rc;
  103. long length;
  104. int  carriage_return;
  105. int  split_line;
  106. int  wordwrap;
  107. int  dirty;
  108. int  old_bcol;
  109. register TDE_WIN *win;   /* put window pointer in a register */
  110. file_infos *file;       /* pointer to file structure in current window */
  111. line_list_ptr new_node;
  112. text_ptr new_line;      /* new line */
  113.  
  114.    rc = OK;
  115.    win = window;
  116.    file = win->file_info;
  117.    length = file->length;
  118.    wordwrap = mode.word_wrap;
  119.    switch (g_status.command) {
  120.       case WordWrap :
  121.          carriage_return = TRUE;
  122.          split_line = FALSE;
  123.          break;
  124.       case AddLine  :
  125.          split_line = carriage_return = FALSE;
  126.          break;
  127.       case SplitLine :
  128.          split_line = carriage_return = TRUE;
  129.          break;
  130.       case Rturn :
  131.       default    :
  132.  
  133.          /*
  134.           * if file is opened in BINARY mode, lets keep the user from
  135.           *   unintentially inserting a line feed into the text.
  136.           */
  137.          if (file->crlf == BINARY)
  138.             return( next_line( win ) );
  139.  
  140.          show_ruler_char( win );
  141.          carriage_return = TRUE;
  142.          split_line = FALSE;
  143.          break;
  144.    }
  145.  
  146.    /*
  147.     * make window temporarily invisible to the un_copy_line function
  148.     */
  149.    new_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  150.    new_line = NULL;
  151.    win->visible = FALSE;
  152.    old_bcol = win->bcol;
  153.    if (rc == OK) {
  154.       new_node->line  = new_line;
  155.       new_node->len   = 0;
  156.       new_node->dirty = FALSE;
  157.  
  158.       if (win->ll->len != EOF) {
  159.          win->file_info->modified = TRUE;
  160.          if (mode.do_backups == TRUE)
  161.             rc = backup_file( win );
  162.          copy_line( win->ll );
  163.          detab_linebuff( );
  164.          len = g_status.line_buff_len;
  165.          split_len = 0;
  166.          if (win->rcol < len)
  167.             win->ll->dirty = TRUE;
  168.  
  169.          source = g_status.line_buff + len;
  170.          if (carriage_return || split_line) {
  171.             if (win->rcol < len) {
  172.                source = g_status.line_buff + win->rcol;
  173.                split_len = len - win->rcol;
  174.                len = win->rcol;
  175.             }
  176.          }
  177.          g_status.line_buff_len = len;
  178.          entab_linebuff( );
  179.          if (un_copy_line( win->ll, win, TRUE ) == OK) {
  180.  
  181.             assert( split_len >= 0 );
  182.             assert( split_len < MAX_LINE_LENGTH );
  183.  
  184.             memmove( g_status.line_buff, source, split_len );
  185.             g_status.line_buff_len = len = split_len;
  186.             g_status.copied = TRUE;
  187.             entab_linebuff( );
  188.          } else
  189.             rc = ERROR;
  190.       } else {
  191.          g_status.line_buff_len = len = 0;
  192.          g_status.copied = TRUE;
  193.       }
  194.  
  195.       if (rc == OK) {
  196.          new_node->line  = new_line;
  197.          new_node->len   = 0;
  198.          new_node->dirty = TRUE;
  199.  
  200.          /*
  201.           * we are somewhere in the list and we need to insert the new node.
  202.           *  if we are anywhere except the EOF node, insert the new node
  203.           *  after the current node.  if the current node is the EOF node,
  204.           *  insert the new node before the EOF node.  this keeps the
  205.           *  EOF node at the end of the list.
  206.           */
  207.          if (win->ll->next != NULL) {
  208.             win->ll->next->prev = new_node;
  209.             new_node->next = win->ll->next;
  210.             win->ll->next = new_node;
  211.             new_node->prev = win->ll;
  212.          } else {
  213.             new_node->next = win->ll;
  214.             if (win->ll->prev != NULL)
  215.                win->ll->prev->next = new_node;
  216.             new_node->prev = win->ll->prev;
  217.             win->ll->prev = new_node;
  218.             if (new_node->prev == NULL)
  219.                win->file_info->line_list = new_node;
  220.             win->ll = new_node;
  221.          }
  222.  
  223.          ++file->length;
  224.          detab_linebuff( );
  225.          entab_linebuff( );
  226.          rc = un_copy_line( new_node, win, FALSE );
  227.          adjust_windows_cursor( win, 1 );
  228.  
  229.          file->dirty = NOT_LOCAL;
  230.          if (length == 0l || wordwrap || win->cline == win->bottom_line)
  231.             file->dirty = GLOBAL;
  232.          else if (!split_line)
  233.             update_line( win );
  234.  
  235.          /*
  236.           * If the cursor is to move down to the next line, then update
  237.           *  the line and column appropriately.
  238.           */
  239.          if (rc == OK  &&  (carriage_return || split_line)) {
  240.             dirty = file->dirty;
  241.             if (win->cline < win->bottom_line)
  242.                win->cline++;
  243.             win->rline++;
  244.             if (win->ll->next != NULL) {
  245.                win->bin_offset += win->ll->len;
  246.                win->ll = win->ll->next;
  247.             }
  248.             rcol = win->rcol;
  249.             old_bcol = win->bcol;
  250.  
  251.             if (win->ll->next != NULL) {
  252.                if (mode.indent || wordwrap) {
  253.                   /*
  254.                    * autoindentation is required. Match the indentation of
  255.                    *  the first line above that is not blank.
  256.                    */
  257.                   add = find_left_margin( wordwrap == FIXED_WRAP ?
  258.                                           win->ll : win->ll->prev, wordwrap );
  259.  
  260.                   assert( add >= 0 );
  261.                   assert( add < MAX_LINE_LENGTH );
  262.  
  263.                   copy_line( win->ll );
  264.                   detab_linebuff( );
  265.                   len = g_status.line_buff_len;
  266.                   source = g_status.line_buff;
  267.                   if (len + add > MAX_LINE_LENGTH)
  268.                      add = MAX_LINE_LENGTH - len;
  269.                   dest = source + add;
  270.  
  271.                   assert( len >= 0);
  272.                   assert( len < MAX_LINE_LENGTH );
  273.  
  274.                   memmove( dest, source, len );
  275.  
  276.                   /*
  277.                    * now put in the autoindent characters
  278.                    */
  279.  
  280.                   assert( add >= 0 );
  281.                   assert( add < MAX_LINE_LENGTH );
  282.  
  283.                   memset( source, ' ', add );
  284.                   win->rcol = add;
  285.                   g_status.line_buff_len += add;
  286.                   entab_linebuff( );
  287.                   rc = un_copy_line( win->ll, win, TRUE );
  288.                } else
  289.                   win->rcol = 0;
  290.             }
  291.             if (rc == OK  &&  split_line) {
  292.                win->rline--;
  293.                win->ll = win->ll->prev;
  294.                if (win->cline > win->top_line + window->ruler)
  295.                   win->cline--;
  296.                win->rcol = rcol;
  297.             }
  298.             check_virtual_col( win, win->rcol, win->ccol );
  299.             if (dirty == GLOBAL || file->dirty == LOCAL || wordwrap)
  300.                file->dirty = GLOBAL;
  301.             else
  302.                file->dirty = dirty;
  303.          }
  304.       } else {
  305.          if (new_node != NULL)
  306.             my_free( new_node );
  307.       }
  308.    } else {
  309.       if (new_node != NULL)
  310.          my_free( new_node );
  311.       error( WARNING, window->bottom_line, main4 );
  312.    }
  313.  
  314.    /*
  315.     * record that file has been modified
  316.     */
  317.    win->visible = TRUE;
  318.    if (rc == OK) {
  319.       if (file->dirty != GLOBAL)
  320.          my_scroll_down( win );
  321.       restore_marked_block( win, 1 );
  322.       show_size( win );
  323.       show_avail_mem( );
  324.       if (old_bcol != win->bcol) {
  325.          make_ruler( win );
  326.          show_ruler( win );
  327.       }
  328.    }
  329.    return( rc );
  330. }
  331.  
  332.  
  333. /*
  334.  * Name:    insert_overwrite
  335.  * Purpose: To make the necessary changes after the user has typed a normal
  336.  *           printable character
  337.  * Date:    June 5, 1991
  338.  * Passed:  window:  pointer to current window
  339.  */
  340. int  insert_overwrite( TDE_WIN *window )
  341. {
  342. char *source;           /* source for block move to make room for c */
  343. char *dest;             /* destination for block move */
  344. int  len;               /* length of current line */
  345. int  pad;               /* padding to add if cursor beyond end of line */
  346. int  add;               /* characters to be added (usually 1 in insert mode) */
  347. register int rcol;
  348. register TDE_WIN *win;  /* put window pointer in a register */
  349. int  rc;
  350.  
  351.    win = window;
  352.    if (win->ll->len == EOF || g_status.key_pressed >= 256)
  353.       rc = OK;
  354.    else {
  355.       rcol = win->rcol;
  356.       /*
  357.        * first check we have room - the editor can not
  358.        *  cope with lines wider than MAX_LINE_LENGTH
  359.        */
  360.       if (rcol >= MAX_LINE_LENGTH) {
  361.          /*
  362.           * cannot insert more characters
  363.           */
  364.          error( WARNING, win->bottom_line, ed2 );
  365.          rc = ERROR;
  366.       } else {
  367.          copy_line( win->ll );
  368.          detab_linebuff( );
  369.  
  370.          /*
  371.           * work out how many characters need to be inserted
  372.           */
  373.          len = g_status.line_buff_len;
  374.          pad = rcol > len ? rcol - len : 0;
  375.  
  376.          if (mode.insert || rcol >= len)
  377.             /*
  378.              * inserted characters, or overwritten characters at the end of
  379.              *  the line, are inserted.
  380.              */
  381.             add = 1;
  382.          else
  383.             /*
  384.              *  and no extra space is required to overwrite existing characters
  385.              */
  386.             add = 0;
  387.  
  388.          /*
  389.           * check that current line would not get too long.
  390.           */
  391.          if (len + pad + add >= MAX_LINE_LENGTH) {
  392.             /*
  393.              * no more room to add
  394.              */
  395.             error( WARNING, win->bottom_line, ed3 );
  396.             rc = ERROR;
  397.          } else {
  398.  
  399.             /*
  400.              * make room for whatever needs to be inserted
  401.              */
  402.             if (pad > 0  || add > 0) {
  403.                source = g_status.line_buff + rcol - pad;
  404.                dest = source + pad + add;
  405.  
  406.                assert( len + pad - rcol >= 0 );
  407.                assert( len + pad - rcol < MAX_LINE_LENGTH );
  408.  
  409.                memmove( dest, source, len + pad - rcol );
  410.  
  411.                /*
  412.                 * put in the required padding
  413.                 */
  414.  
  415.                assert( pad >= 0 );
  416.                assert( pad < MAX_LINE_LENGTH );
  417.  
  418.                memset( source, ' ', pad );
  419.             }
  420.             g_status.line_buff[rcol] = (char)g_status.key_pressed;
  421.             g_status.line_buff_len += pad + add;
  422.             entab_linebuff( );
  423.  
  424.             /*
  425.              * always increment the real column (rcol) then adjust the
  426.              * logical and base column as needed.   show the changed line
  427.              * in all but the LOCAL window.  In the LOCAL window, there are
  428.              * two cases:  1) update the line, or 2) redraw the window if
  429.              * cursor goes too far right.
  430.              */
  431.             win->file_info->dirty = NOT_LOCAL;
  432.             win->ll->dirty = TRUE;
  433.             show_changed_line( win );
  434.             if (win->ccol < win->end_col) {
  435.                show_curl_line( win );
  436.                show_ruler_char( win );
  437.                win->ccol++;
  438.             } else {
  439.                win->bcol++;
  440.                win->file_info->dirty = LOCAL;
  441.                make_ruler( win );
  442.                show_ruler( win );
  443.             }
  444.             rcol++;
  445.          }
  446.  
  447.          /*
  448.           * record that file has been modified and adjust cursors,
  449.           * file start and end pointers as needed.
  450.           */
  451.          check_virtual_col( win, rcol, win->ccol );
  452.          win->file_info->modified = TRUE;
  453.          if (mode.word_wrap) {
  454.             add = mode.right_justify;
  455.             mode.right_justify = FALSE;
  456.             g_status.command = FormatText;
  457.             word_wrap( win );
  458.             mode.right_justify = add;
  459.          }
  460.          rc = OK;
  461.       }
  462.    }
  463.    return( rc );
  464. }
  465.  
  466.  
  467. /*
  468.  * Name:    join_line
  469.  * Purpose: To join current line and line below at cursor
  470.  * Date:    June 5, 1991
  471.  * Passed:  window:  pointer to current window
  472.  * Notes:   trunc the line.  then, join with line below, if it exists.
  473.  */
  474. int  join_line( TDE_WIN *window )
  475. {
  476. int  len;               /* length of current line */
  477. int  new_len;           /* length of the joined lines */
  478. int  next_len;          /* length of the line below current line */
  479. text_ptr q;             /* next line in file */
  480. text_ptr tab_free;      /* next line in file -- with the tabs removed */
  481. int  pad;               /* padding spaces required */
  482. register TDE_WIN *win;   /* put window pointer in a register */
  483. TDE_WIN *wp;
  484. line_list_ptr next_node;
  485. int  rc;
  486.  
  487.    win = window;
  488.    if (win->ll->len == EOF  ||  win->ll->next->len == EOF)
  489.       return( ERROR );
  490.  
  491.    rc = OK;
  492.  
  493.    assert( win->ll->next != NULL );
  494.  
  495.    next_node = win->ll->next;
  496.    load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  497.    copy_line( win->ll );
  498.    detab_linebuff( );
  499.  
  500.    /*
  501.     * if cursor is in line before eol, reset len to rcol
  502.     */
  503.    if (win->rcol < (len = g_status.line_buff_len))
  504.       len = win->rcol;
  505.  
  506.    /*
  507.     * calculate needed padding
  508.     */
  509.    pad = win->rcol > len ? win->rcol - len : 0;
  510.  
  511.    assert( pad >= 0 );
  512.    assert( pad < MAX_LINE_LENGTH );
  513.  
  514.    /*
  515.     * if there any tabs in the next line, expand them because we
  516.     *   probably have to redo them anyway.
  517.     */
  518.    next_len = next_node->len;
  519.    tab_free = detab_a_line( next_node->line, &next_len );
  520.  
  521.    assert( next_len >= 0 );
  522.    assert( next_len < MAX_LINE_LENGTH );
  523.    assert( len >= 0 );
  524.    assert( len < MAX_LINE_LENGTH );
  525.  
  526.    /*
  527.     * check room to combine lines
  528.     */
  529.    new_len = len + pad + next_len;
  530.    if (new_len >= MAX_LINE_LENGTH) {
  531.       /*
  532.        * cannot combine lines.
  533.        */
  534.       error( WARNING, win->bottom_line, ed4 );
  535.       rc = ERROR;
  536.    } else {
  537.       if (mode.do_backups == TRUE) {
  538.          win->file_info->modified = TRUE;
  539.          rc = backup_file( win );
  540.       }
  541.       q = (text_ptr)(g_status.line_buff + len);
  542.       /*
  543.        * insert padding
  544.        */
  545.       if (pad > 0) {
  546.          while (pad--)
  547.             *q++ = ' ';
  548.       }
  549.       my_memcpy( q, tab_free, next_len );
  550.       g_status.line_buff_len = new_len;
  551.       entab_linebuff( );
  552.  
  553.       if ((rc = un_copy_line( win->ll, win, FALSE )) == OK) {
  554.  
  555.          if (next_node->next != NULL)
  556.             next_node->next->prev = win->ll;
  557.          win->ll->next = next_node->next;
  558.          win->ll->dirty = TRUE;
  559.  
  560.          --win->file_info->length;
  561.          ++win->rline;
  562.          adjust_windows_cursor( win, -1 );
  563.          restore_marked_block( win, -1 );
  564.          --win->rline;
  565.  
  566.          wp = g_status.window_list;
  567.          while (wp != NULL) {
  568.             if (wp->file_info == win->file_info) {
  569.                /*
  570.                 * make sure none of the window pointers point to the
  571.                 *   node we are about to delete.
  572.                 */
  573.                if (wp != win) {
  574.                   if (wp->ll == next_node)
  575.                      wp->ll = win->ll->next;
  576.                }
  577.             }
  578.             wp = wp->next;
  579.          }
  580.  
  581.          /*
  582.           * now, it's safe to delete the next_node line as well as
  583.           *   the next node.
  584.           */
  585.          if (next_node->line != NULL)
  586.             my_free( next_node->line );
  587.          my_free( next_node );
  588.  
  589.          show_size( win );
  590.          show_avail_mem( );
  591.          win->file_info->dirty = GLOBAL;
  592.       }
  593.    }
  594.    return( rc );
  595. }
  596.  
  597.  
  598. /*
  599.  * Name:    word_delete
  600.  * Purpose: To delete from the cursor to the start of the next word.
  601.  * Date:    September 1, 1991
  602.  * Passed:  window:  pointer to current window
  603.  * Notes:   If the cursor is at the right of the line, then combine the
  604.  *           current line with the next one, leaving the cursor where it
  605.  *           is.
  606.  *          If the cursor is on an alphanumeric character, then all
  607.  *           subsequent alphanumeric characters are deleted.
  608.  *          If the cursor is on a space, then all subsequent spaces
  609.  *           are deleted.
  610.  *          If the cursor is on a punctuation character, then all
  611.  *           subsequent punctuation characters are deleted.
  612.  */
  613. int  word_delete( TDE_WIN *window )
  614. {
  615. int  len;               /* length of current line */
  616. int  count;             /* number of characters deleted from line */
  617. register int start;     /* column that next word starts in */
  618. char *source;           /* source for block move to delete word */
  619. char *dest;             /* destination for block move */
  620. text_ptr p;
  621. register TDE_WIN *win;   /* put window pointer in a register */
  622. int  rc;
  623.  
  624.    win = window;
  625.    if (win->rline > win->file_info->length  || win->ll->len == EOF)
  626.       return( ERROR );
  627.  
  628.    rc = OK;
  629.    copy_line( win->ll );
  630.    detab_linebuff( );
  631.    if (win->rcol >= (len = g_status.line_buff_len)) {
  632.       rc = join_line( win );
  633.       if (rc == OK) {
  634.          p = win->ll->line;
  635.          if (p != NULL) {
  636.             p += win->rcol;
  637.             if (win->rcol < win->ll->len) {
  638.                len = win->ll->len - win->rcol;
  639.                load_undo_buffer( win->file_info, p, len );
  640.             }
  641.          }
  642.       }
  643.    } else {
  644.  
  645.       assert( len >= 0);
  646.       assert( len < MAX_LINE_LENGTH );
  647.  
  648.       /*
  649.        * normal word delete
  650.        *
  651.        * find the start of the next word
  652.        */
  653.       start = win->rcol;
  654.       if (bj_isspace( g_status.line_buff[start] )) {
  655.          /*
  656.           * the cursor was on a space, so eat all consecutive spaces
  657.           *  from the cursor onwards.
  658.           */
  659.          while (start < len  &&  bj_isspace( g_status.line_buff[start] ))
  660.             ++start;
  661.       } else {
  662.          /*
  663.           * eat all consecutive characters in the same class (spaces
  664.           *  are considered to be in the same class as the cursor
  665.           *  character)
  666.           */
  667.          while (start < len  &&  !bj_isspace( g_status.line_buff[start] ))
  668.             ++start;
  669.          while (start < len  &&  bj_isspace( g_status.line_buff[start] ))
  670.             ++start;
  671.       }
  672.  
  673.       /*
  674.        * move text to delete word
  675.        */
  676.       count = start - win->rcol;
  677.       source = g_status.line_buff + start;
  678.       dest = g_status.line_buff + win->rcol;
  679.  
  680.       assert( len - start >= 0 );
  681.  
  682.       memmove( dest, source, len - start );
  683.       g_status.line_buff_len = len - count;
  684.       entab_linebuff( );
  685.       win->file_info->modified = TRUE;
  686.       win->file_info->dirty = GLOBAL;
  687.       win->ll->dirty = TRUE;
  688.  
  689.       /*
  690.        * word_delete is also called by the word processing functions to get
  691.        *   rid of spaces.
  692.        */
  693.       if (g_status.command == WordDelete)
  694.          show_changed_line( win );
  695.    }
  696.    return( rc );
  697. }
  698.  
  699.  
  700. /*
  701.  * Name:    dup_line
  702.  * Purpose: Duplicate current line
  703.  * Date:    June 5, 1991
  704.  * Passed:  window:  pointer to current window
  705.  * Notes:   cursor stays on current line
  706.  */
  707. int  dup_line( TDE_WIN *window )
  708. {
  709. register int len;       /* length of current line */
  710. text_ptr p;
  711. register TDE_WIN *win;   /* put window pointer in a register */
  712. line_list_ptr next_node;
  713. int  rc;
  714.  
  715.    win = window;
  716.  
  717.    /*
  718.     * don't dup a NULL line
  719.     */
  720.    if (win->rline > win->file_info->length  ||  win->ll->len == EOF)
  721.       return( ERROR );
  722.  
  723.    entab_linebuff( );
  724.    rc = un_copy_line( win->ll, win, TRUE );
  725.    len = win->ll->len;
  726.  
  727.    assert( len >= 0);
  728.    assert( len < MAX_LINE_LENGTH );
  729.  
  730.    p = NULL;
  731.    next_node = NULL;
  732.    if (rc == OK) {
  733.       p = (text_ptr)my_malloc( len, &rc );
  734.       next_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  735.    }
  736.  
  737.    if (rc == OK) {
  738.       win->file_info->modified = TRUE;
  739.       if (mode.do_backups == TRUE)
  740.          rc = backup_file( win );
  741.       ++win->file_info->length;
  742.  
  743.       if (len > 0)
  744.          my_memcpy( p, win->ll->line, len );
  745.  
  746.       next_node->line  = p;
  747.       next_node->dirty = TRUE;
  748.       next_node->len   = len;
  749.  
  750.       if (win->ll->next != NULL)
  751.          win->ll->next->prev = next_node;
  752.  
  753.       next_node->next = win->ll->next;
  754.       next_node->prev = win->ll;
  755.       win->ll->next = next_node;
  756.  
  757.       adjust_windows_cursor( win, 1 );
  758.  
  759.       /*
  760.        * if current line is the bottom line, we can't see the dup line because
  761.        * cursor doesn't move and dup line is added after current line.
  762.        */
  763.       if  (win->cline != win->bottom_line)
  764.          my_scroll_down( win );
  765.       win->file_info->dirty = NOT_LOCAL;
  766.  
  767.       /*
  768.        * record that file has been modified
  769.        */
  770.       restore_marked_block( win, 1 );
  771.       show_size( win );
  772.       show_avail_mem( );
  773.    } else {
  774.       /*
  775.        * cannot duplicate line
  776.        */
  777.       if (p != NULL)
  778.          my_free( p );
  779.       if (next_node != NULL)
  780.          my_free( next_node );
  781.       error( WARNING, win->bottom_line, ed5 );
  782.    }
  783.    return( rc );
  784. }
  785.  
  786.  
  787. /*
  788.  * Name:    back_space
  789.  * Purpose: To delete the character to the left of the cursor.
  790.  * Date:    June 5, 1991
  791.  * Passed:  window:  pointer to current window
  792.  * Notes:   If the cursor is at the left of the line, then combine the
  793.  *           current line with the previous one.
  794.  *          If in indent mode, and the cursor is on the first non-blank
  795.  *           character of the line, then match the indentation of an
  796.  *           earlier line.
  797.  */
  798. int  back_space( TDE_WIN *window )
  799. {
  800. int  rc;                /* return code */
  801. int  len;               /* length of the current line */
  802. char *source;           /* source of block move to delete character */
  803. char *dest;             /* destination of block move */
  804. text_ptr p;             /* previous line in file */
  805. int  plen;              /* length of previous line */
  806. int  del_count;         /* number of characters to delete */
  807. int  pos;               /* the position of the first non-blank char */
  808. register int rcol;
  809. int  ccol;
  810. int  old_bcol;
  811. register TDE_WIN *win;  /* put window pointer in a register */
  812. TDE_WIN *wp;
  813. line_list_ptr temp_ll;
  814.  
  815.    win = window;
  816.    if (win->rline > win->file_info->length || win->ll->len == EOF)
  817.       return( ERROR );
  818.    rc = OK;
  819.    copy_line( win->ll );
  820.    detab_linebuff( );
  821.    len = g_status.line_buff_len;
  822.    rcol = win->rcol;
  823.    ccol = win->ccol;
  824.    old_bcol = win->bcol;
  825.    if (rcol == 0) {
  826.       if (win->rline > 1) {
  827.          /*
  828.           * combine this line with the previous, if any
  829.           */
  830.  
  831.          assert( win->ll->prev != NULL );
  832.  
  833.          p = win->ll->prev->line;
  834.          plen = win->ll->prev->len;
  835.          if (len + 2 + plen >= MAX_LINE_LENGTH) {
  836.             /*
  837.              * cannot combine lines
  838.              */
  839.             error( WARNING, win->bottom_line, ed4 );
  840.             return( ERROR );
  841.          }
  842.  
  843.          win->file_info->modified = TRUE;
  844.          if ((rc = un_copy_line( win->ll, win, TRUE )) == OK) {
  845.             --win->rline;
  846.             win->ll = win->ll->prev;
  847.             win->bin_offset -= win->ll->len;
  848.             win->ll->dirty = TRUE;
  849.             copy_line( win->ll );
  850.             detab_linebuff( );
  851.             len = g_status.line_buff_len;
  852.             rcol = len;
  853.  
  854.             p = win->ll->next->line;
  855.             plen = win->ll->next->len;
  856.  
  857.             /*
  858.              * copy previous line into new previous line.
  859.              */
  860.             assert( plen >= 0 );
  861.             assert( len  >= 0 );
  862.  
  863.             my_memcpy( g_status.line_buff+len, p, plen );
  864.             g_status.line_buff_len = len + plen;
  865.  
  866.             load_undo_buffer( win->file_info, p, plen );
  867.             if (p != NULL)
  868.                my_free( p );
  869.  
  870.             temp_ll = win->ll->next;
  871.  
  872.             if (temp_ll->prev != NULL)
  873.                temp_ll->prev->next = temp_ll->next;
  874.             temp_ll->next->prev = temp_ll->prev;
  875.  
  876.             --win->file_info->length;
  877.             ++win->rline;
  878.             restore_marked_block( win, -1 );
  879.             adjust_windows_cursor( win, -1 );
  880.             --win->rline;
  881.  
  882.             wp = g_status.window_list;
  883.             while (wp != NULL) {
  884.                if (wp->file_info == win->file_info) {
  885.                   if (wp != win) {
  886.                      if (wp->ll == temp_ll)
  887.                         wp->ll = win->ll->next;
  888.                   }
  889.                }
  890.                wp = wp->next;
  891.             }
  892.  
  893.             my_free( temp_ll );
  894.  
  895.             if (win->cline > win->top_line + win->ruler)
  896.                --win->cline;
  897.  
  898.             /*
  899.              * make sure cursor stays on the screen, at the end of the
  900.              *  previous line
  901.              */
  902.             ccol = rcol - win->bcol;
  903.             show_size( win );
  904.             show_avail_mem( );
  905.             check_virtual_col( win, rcol, ccol );
  906.             win->file_info->dirty = GLOBAL;
  907.             make_ruler( win );
  908.             show_ruler( win );
  909.          }
  910.       } else
  911.          return( ERROR );
  912.    } else {
  913.       /*
  914.        * normal delete
  915.        *
  916.        * find out how much to delete (depends on indent mode)
  917.        */
  918.       del_count = 1;   /* the default */
  919.       if (mode.indent) {
  920.          /*
  921.           * indent only happens if the cursor is on the first
  922.           *  non-blank character of the line
  923.           */
  924.          pos = first_non_blank( (text_ptr)g_status.line_buff, len );
  925.          if (pos == rcol  ||
  926.                          is_line_blank( (text_ptr)g_status.line_buff, len )) {
  927.             /*
  928.              * now work out how much to indent
  929.              */
  930.             temp_ll = win->ll->prev;
  931.             for (; temp_ll != NULL; temp_ll=temp_ll->prev) {
  932.                p = temp_ll->line;
  933.                plen = first_non_blank( p, temp_ll->len );
  934.                if (plen < rcol  &&  plen != temp_ll->len) {
  935.                   /*
  936.                    * found the line to match
  937.                    */
  938.                   del_count = rcol - plen;
  939.                   break;
  940.                }
  941.             }
  942.          }
  943.       }
  944.  
  945.       /*
  946.        * move text to delete char(s), unless no chars actually there
  947.        */
  948.       if (rcol - del_count < len) {
  949.          dest = g_status.line_buff + rcol - del_count;
  950.          if (rcol > len) {
  951.             source = g_status.line_buff + len;
  952.             pos = 0;
  953.             len = (rcol + 1) - del_count;
  954.          } else {
  955.             source = g_status.line_buff + rcol;
  956.             pos = len - rcol;
  957.             len = len - del_count;
  958.          }
  959.  
  960.          assert( pos >= 0 );
  961.          assert( len >= 0 );
  962.          assert( len <= MAX_LINE_LENGTH );
  963.  
  964.          memmove( dest, source, pos );
  965.          g_status.line_buff_len = len;
  966.          entab_linebuff( );
  967.       }
  968.       rcol -= del_count;
  969.       ccol -= del_count;
  970.       win->file_info->dirty = NOT_LOCAL;
  971.       win->ll->dirty = TRUE;
  972.       show_ruler_char( win );
  973.       show_changed_line( win );
  974.       check_virtual_col( win, rcol, ccol );
  975.       if (!win->file_info->dirty)
  976.          show_curl_line( win );
  977.       if (old_bcol != win->bcol) {
  978.          make_ruler( win );
  979.          show_ruler( win );
  980.       }
  981.    }
  982.    win->file_info->modified = TRUE;
  983.    return( rc );
  984. }
  985.  
  986.  
  987. /*
  988.  * Name:    line_kill
  989.  * Purpose: To delete the line the cursor is on.
  990.  * Date:    June 5, 1991
  991.  * Passed:  window:  pointer to current window
  992.  * Notes:   win->ll->s == NULL then do not do a
  993.  *          line kill (can't kill a NULL line).
  994.  */
  995. int  line_kill( TDE_WIN *window )
  996. {
  997. register TDE_WIN *win;   /* put window pointer in a register */
  998. register TDE_WIN *wp;
  999. line_list_ptr killed_node;
  1000. int  rc;
  1001.  
  1002.    win = window;
  1003.    killed_node = win->ll;
  1004.    rc = OK;
  1005.    if (killed_node->len != EOF) {
  1006.       win->file_info->modified = TRUE;
  1007.       if (mode.do_backups == TRUE)
  1008.          rc = backup_file( win );
  1009.  
  1010.       if (rc == OK) {
  1011.          load_undo_buffer( win->file_info,
  1012.             g_status.copied ? (text_ptr)g_status.line_buff : killed_node->line,
  1013.             g_status.copied ? g_status.line_buff_len       : killed_node->len );
  1014.  
  1015.          --win->file_info->length;
  1016.  
  1017.          win->ll = win->ll->next;
  1018.  
  1019.          if (killed_node->prev != NULL)
  1020.             killed_node->prev->next = killed_node->next;
  1021.          else
  1022.             win->file_info->line_list = win->ll;
  1023.  
  1024.          killed_node->next->prev = killed_node->prev;
  1025.  
  1026.          wp = g_status.window_list;
  1027.          while (wp != NULL) {
  1028.             if (wp->file_info == win->file_info) {
  1029.                if (wp != win) {
  1030.                   if (wp->ll == killed_node)
  1031.                      wp->ll = win->ll;
  1032.                }
  1033.             }
  1034.             wp = wp->next;
  1035.          }
  1036.  
  1037.          /*
  1038.           * free the line and the node
  1039.           */
  1040.          if (killed_node->line != NULL)
  1041.             my_free( killed_node->line );
  1042.          my_free( killed_node );
  1043.  
  1044.          win->file_info->dirty = NOT_LOCAL;
  1045.  
  1046.          g_status.copied = FALSE;
  1047.          /*
  1048.           * move all cursors one according to i, restore begin and end block
  1049.           */
  1050.          adjust_windows_cursor( win, -1 );
  1051.          restore_marked_block( win, -1 );
  1052.  
  1053.          /*
  1054.           * we are not doing a GLOBAL update, so update current window here
  1055.           */
  1056.          if (win->file_info->dirty == NOT_LOCAL)
  1057.             my_scroll_down( win );
  1058.          show_size( win );
  1059.          show_avail_mem( );
  1060.       }
  1061.    } else
  1062.       rc = ERROR;
  1063.    return( rc );
  1064. }
  1065.  
  1066.  
  1067. /*
  1068.  * Name:    char_del_under
  1069.  * Purpose: To delete the character under the cursor.
  1070.  * Date:    June 5, 1991
  1071.  * Passed:  window:  pointer to current window
  1072.  * Notes:   If the cursor is beyond the end of the line, then this
  1073.  *           command is ignored.
  1074.  *          DeleteChar and StreamDeleteChar use this function.
  1075.  */
  1076. int  char_del_under( TDE_WIN *window )
  1077. {
  1078. char *source;    /* source of block move to delete character */
  1079. int  len;
  1080. register TDE_WIN *win;   /* put window pointer in a register */
  1081.  
  1082.    win = window;
  1083.    if (win->rline > win->file_info->length || win->ll->len == EOF)
  1084.       return( OK );
  1085.    copy_line( win->ll );
  1086.    detab_linebuff( );
  1087.    if (win->rcol < (len = g_status.line_buff_len)) {
  1088.       /*
  1089.        * move text to delete using buffer
  1090.        */
  1091.       source = g_status.line_buff + win->rcol + 1;
  1092.  
  1093.       assert( len - win->rcol >= 0 );
  1094.  
  1095.       memmove( source-1, source, len - win->rcol );
  1096.       --g_status.line_buff_len;
  1097.       entab_linebuff( );
  1098.       win->file_info->dirty    = GLOBAL;
  1099.       win->file_info->modified = TRUE;
  1100.       win->ll->dirty = TRUE;
  1101.       show_changed_line( win );
  1102.    } else if (g_status.command == StreamDeleteChar)
  1103.       join_line( win );
  1104.    return( OK );
  1105. }
  1106.  
  1107.  
  1108. /*
  1109.  * Name:    eol_kill
  1110.  * Purpose: To delete everything from the cursor to the end of the line.
  1111.  * Date:    June 5, 1991
  1112.  * Passed:  window:  pointer to current window
  1113.  * Notes:   If the cursor is beyond the end of the line, then this
  1114.  *           command is ignored.
  1115.  */
  1116. int  eol_kill( TDE_WIN *window )
  1117. {
  1118. register TDE_WIN *win;   /* put window pointer in a register */
  1119.  
  1120.    win = window;
  1121.    if (win->rline > win->file_info->length  ||  win->ll->len == EOF)
  1122.       return( OK );
  1123.    copy_line( win->ll );
  1124.    detab_linebuff( );
  1125.    load_undo_buffer( win->file_info, (text_ptr)g_status.line_buff,
  1126.                      g_status.line_buff_len );
  1127.    if (win->rcol < g_status.line_buff_len) {
  1128.       /*
  1129.        * truncate to delete rest of line
  1130.        */
  1131.       g_status.line_buff_len = win->rcol;
  1132.       entab_linebuff( );
  1133.       win->file_info->dirty = GLOBAL;
  1134.       win->ll->dirty = TRUE;
  1135.       show_changed_line( win );
  1136.    }
  1137.    return( OK );
  1138. }
  1139.  
  1140.  
  1141. /*
  1142.  * Name:    undo_line
  1143.  * Purpose: To retrieve unaltered line if possible.
  1144.  * Date:    June 5, 1991
  1145.  * Passed:  window:  pointer to current window
  1146.  * Notes:   Changes are made to the line buffer so the underlying text has
  1147.  *          not changed.  Put the unchanged line from the file into the
  1148.  *          line buffer and display it.
  1149.  */
  1150. int  undo_line( TDE_WIN *window )
  1151. {
  1152. register TDE_WIN *win;   /* put window pointer in a register */
  1153.  
  1154.    win = window;
  1155.    if (win->rline <= win->file_info->length  &&  win->ll->len != EOF &&
  1156.                             g_status.copied) {
  1157.       g_status.copied = FALSE;
  1158.       copy_line( win->ll );
  1159.       detab_linebuff( );
  1160.       win->file_info->dirty = GLOBAL;
  1161.       show_changed_line( win );
  1162.    }
  1163.    return( OK );
  1164. }
  1165.  
  1166.  
  1167. /*
  1168.  * Name:    undo
  1169.  * Purpose: To retrieve (pop) a line from the undo stack
  1170.  * Date:    September 26, 1991
  1171.  * Passed:  window:  pointer to current window
  1172.  * Notes:   Insert an empty line into the file then pop the line in the undo
  1173.  *          stack.  When we pop line 0, there are no more lines on the stack.
  1174.  *          Set the stack pointer to -1 to indicate an empty stack.
  1175.  */
  1176. int  undo( TDE_WIN *window )
  1177. {
  1178. register TDE_WIN *win;   /* put window pointer in a register */
  1179. line_list_ptr node;
  1180.  
  1181.    win = window;
  1182.    if (win->file_info->undo_count > 0) {
  1183.       entab_linebuff( );
  1184.       if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1185.          return( ERROR );
  1186.  
  1187.       node = win->file_info->undo_top;
  1188.       win->file_info->undo_top = node->next;
  1189.       win->file_info->undo_top->prev = NULL;
  1190.       --win->file_info->undo_count;
  1191.  
  1192.       node->next = node->prev = NULL;
  1193.  
  1194.       ++win->file_info->length;
  1195.  
  1196.       if (win->ll->prev != NULL)
  1197.          win->ll->prev->next = node;
  1198.       node->prev = win->ll->prev;
  1199.  
  1200.       win->ll->prev = node;
  1201.       node->next = win->ll;
  1202.       win->ll = node;
  1203.       win->ll->dirty = TRUE;
  1204.  
  1205.       if (win->ll->prev == NULL)
  1206.          win->file_info->line_list = win->ll;
  1207.  
  1208.       adjust_windows_cursor( win, 1 );
  1209.  
  1210.       /*
  1211.        * we have now undeleted a line.  increment the file length and display
  1212.         * it.
  1213.        */
  1214.       win->file_info->dirty = GLOBAL;
  1215.       show_size( win );
  1216.       show_avail_mem( );
  1217.    }
  1218.    return( OK );
  1219. }
  1220.  
  1221.  
  1222. /*
  1223.  * Name:    beg_next_line
  1224.  * Purpose: To move the cursor to the beginning of the next line.
  1225.  * Date:    October 4, 1991
  1226.  * Passed:  window:  pointer to current window
  1227.  */
  1228. int  beg_next_line( TDE_WIN *window )
  1229. {
  1230. int  rc;
  1231.  
  1232.    window->rcol = 0;
  1233.    rc = prepare_move_down( window );
  1234.    check_virtual_col( window, window->rcol, window->ccol );
  1235.    cursor_sync( window );
  1236.    make_ruler( window );
  1237.    show_ruler( window );
  1238.    return( rc );
  1239. }
  1240.  
  1241.  
  1242. /*
  1243.  * Name:    next_line
  1244.  * Purpose: To move the cursor to the first character of the next line.
  1245.  * Date:    October 4, 1991
  1246.  * Passed:  window:  pointer to current window
  1247.  */
  1248. int  next_line( TDE_WIN *window )
  1249. {
  1250. register int rcol;
  1251. register TDE_WIN *win;   /* put window pointer in a register */
  1252. int  rc;
  1253.  
  1254.    win = window;
  1255.    rc = prepare_move_down( win );
  1256.    rcol = first_non_blank( win->ll->line, win->ll->len );
  1257.    check_virtual_col( win, rcol, win->ccol );
  1258.    cursor_sync( win );
  1259.    make_ruler( win );
  1260.    show_ruler( win );
  1261.    return( rc );
  1262. }
  1263.  
  1264.  
  1265. /*
  1266.  * Name:    home
  1267.  * Purpose: To move the cursor to the left of the current line.
  1268.  * Date:    June 5, 1991
  1269.  * Passed:  window:  pointer to current window
  1270.  * Notes:   this routine is made a little more complicated with cursor sync.
  1271.  *            if the g_status.copied flag is set we need to see from what file
  1272.  *            the line_buff was copied.
  1273.  */
  1274. int  home( TDE_WIN *window )
  1275. {
  1276. register int rcol;
  1277. register TDE_WIN *win;   /* put window pointer in a register */
  1278. text_ptr p;
  1279.  
  1280.    win = window;
  1281.    if (g_status.copied && win->file_info == g_status.current_window->file_info){
  1282.       rcol = first_non_blank( (text_ptr)g_status.line_buff,
  1283.                                         g_status.line_buff_len );
  1284.       if (is_line_blank( (text_ptr)g_status.line_buff, g_status.line_buff_len))
  1285.          rcol = 0;
  1286.    } else {
  1287.       p = win->ll->line;
  1288.       if (p == NULL)
  1289.          rcol = 0;
  1290.       else {
  1291.          rcol = first_non_blank( p, win->ll->len );
  1292.          if (is_line_blank( p, win->ll->len ))
  1293.             rcol = 0;
  1294.       }
  1295.    }
  1296.    if (win->rcol == rcol)
  1297.       rcol = 0;
  1298.    check_virtual_col( win, rcol, win->ccol );
  1299.    cursor_sync( win );
  1300.    make_ruler( win );
  1301.    show_ruler( win );
  1302.    return( OK );
  1303. }
  1304.  
  1305.  
  1306. /*
  1307.  * Name:    goto_eol
  1308.  * Purpose: To move the cursor to the eol character of the current line.
  1309.  * Date:    June 5, 1991
  1310.  * Passed:  window:  pointer to current window
  1311.  * Notes:   this routine is made a little more complicated with cursor sync.
  1312.  *            if the g_status.copied flag is set we need to see from what file
  1313.  *            the line_buff was copied.
  1314.  */
  1315. int  goto_eol( TDE_WIN *window )
  1316. {
  1317. register int rcol;
  1318. register TDE_WIN *win;   /* put window pointer in a register */
  1319.  
  1320.    win = window;
  1321.    rcol = find_end( win->ll->line, win->ll->len );
  1322.    if (g_status.copied) {
  1323.       if (win->file_info == g_status.current_window->file_info)
  1324.          rcol = find_end( (text_ptr)g_status.line_buff, g_status.line_buff_len);
  1325.    }
  1326.    win->ccol = win->start_col + rcol - win->bcol;
  1327.    check_virtual_col( win, rcol, win->ccol );
  1328.    cursor_sync( win );
  1329.    make_ruler( win );
  1330.    show_ruler( win );
  1331.    return( OK );
  1332. }
  1333.  
  1334.  
  1335. /*
  1336.  * Name:    goto_top
  1337.  * Purpose: To move the cursor to the top of the current window.
  1338.  * Date:    June 5, 1991
  1339.  * Passed:  window:  pointer to current window
  1340.  * Notes:   If the start of the file occurs before the top of the window,
  1341.  *           then the start of the file is moved to the top of the window.
  1342.  */
  1343. int  goto_top( TDE_WIN *window )
  1344. {
  1345. register TDE_WIN *win;   /* put window pointer in a register */
  1346.  
  1347.    win = window;
  1348.    entab_linebuff( );
  1349.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1350.       return( ERROR );
  1351.    update_line( win );
  1352.    for (; win->cline > win->top_line+win->ruler; win->cline--,win->rline--) {
  1353.       if (win->rline <= 1L)
  1354.          break;
  1355.       else {
  1356.          win->ll = win->ll->prev;
  1357.          win->bin_offset -= win->ll->len;
  1358.       }
  1359.    }
  1360.    show_curl_line( win );
  1361.    cursor_sync( win );
  1362.    return( OK );
  1363. }
  1364.  
  1365.  
  1366. /*
  1367.  * Name:    goto_bottom
  1368.  * Purpose: To move the cursor to the bottom of the current window.
  1369.  * Date:    June 5, 1991
  1370.  * Passed:  window:  pointer to current window
  1371.  */
  1372. int  goto_bottom( TDE_WIN *window )
  1373. {
  1374. register TDE_WIN *win;   /* put window pointer in a register */
  1375. int  at_top;
  1376.  
  1377.    win = window;
  1378.    entab_linebuff( );
  1379.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1380.       return( ERROR );
  1381.    if (win->ll->len == EOF) {
  1382.       if (win->rline > 1) {
  1383.          at_top = FALSE;
  1384.          if (win->cline == win->top_line + win->ruler) {
  1385.             win->file_info->dirty = LOCAL;
  1386.             at_top = TRUE;
  1387.          }
  1388.          if (!at_top)
  1389.             update_line( win );
  1390.          --win->rline;             /* ALWAYS decrement line counter */
  1391.          win->ll = win->ll->prev;
  1392.          win->bin_offset -= win->ll->len;
  1393.          if (!at_top) {
  1394.             --win->cline;          /* we aren't at top of screen - so move up */
  1395.             show_curl_line( win );
  1396.          }
  1397.       }
  1398.    } else {
  1399.       update_line( win );
  1400.       for (; win->cline < win->bottom_line; win->cline++,win->rline++) {
  1401.          if (win->ll == NULL || win->ll->next == NULL || win->ll->next->len == EOF)
  1402.             break;
  1403.          else {
  1404.             win->bin_offset += win->ll->len;
  1405.             win->ll = win->ll->next;
  1406.          }
  1407.       }
  1408.       show_curl_line( win );
  1409.    }
  1410.    cursor_sync( win );
  1411.    return( OK );
  1412. }
  1413.  
  1414.  
  1415. /*
  1416.  * Name:    set_tabstop
  1417.  * Purpose: To set the current interval between tab stops
  1418.  * Date:    October 1, 1989
  1419.  * Notes:   Tab interval must be reasonable, and this function will
  1420.  *           not allow tabs more than g_display.ncols / 2.
  1421.  */
  1422. int  set_tabstop( TDE_WIN *window )
  1423. {
  1424. int  tab;               /* new tab interval */
  1425. register int rc;
  1426. register file_infos *file;
  1427. char temp[MAX_COLS+2];
  1428.  
  1429.    my_ltoa( mode.ltab_size, temp, 10 );
  1430.    /*
  1431.     * tab interval:
  1432.     */
  1433.    rc = get_name( ed7a, window->bottom_line, temp, g_display.message_color );
  1434.    if (rc == OK   &&  *temp != '\0') {
  1435.       tab = atoi( temp );
  1436.       if (tab < g_display.ncols / 2) {
  1437.          mode.ltab_size = tab;
  1438.          if (mode.inflate_tabs) {
  1439.             for (file=g_status.file_list; file != NULL; file=file->next)
  1440.                file->dirty = GLOBAL;
  1441.          }
  1442.       } else {
  1443.          /*
  1444.           * tab size too long
  1445.           */
  1446.          error( WARNING, window->bottom_line, ed8 );
  1447.          rc = ERROR;
  1448.       }
  1449.    }
  1450.  
  1451.    my_ltoa( mode.ptab_size, temp, 10 );
  1452.    /*
  1453.     * tab interval:
  1454.     */
  1455.    rc = get_name( ed7b, window->bottom_line, temp, g_display.message_color );
  1456.    if (rc == OK  &&  *temp != '\0') {
  1457.       tab = atoi( temp );
  1458.       if (tab < g_display.ncols / 2) {
  1459.          mode.ptab_size = tab;
  1460.          show_tab_modes( );
  1461.          if (mode.inflate_tabs) {
  1462.             for (file=g_status.file_list; file != NULL; file=file->next)
  1463.                file->dirty = GLOBAL;
  1464.          }
  1465.       } else {
  1466.          /*
  1467.           * tab size too long
  1468.           */
  1469.          error( WARNING, window->bottom_line, ed8 );
  1470.          rc = ERROR;
  1471.       }
  1472.    }
  1473.    return( rc );
  1474. }
  1475.  
  1476.  
  1477. /*
  1478.  * Name:    show_line_col
  1479.  * Purpose: show current real line and column of current cursor position
  1480.  * Date:    June 5, 1991
  1481.  * Passed:  window:  pointer to current window
  1482.  * Notes:   Blank old position and display new position.  current line and
  1483.  *          column may take up to 12 columns, which allows the display of
  1484.  *          9,999 columns and 9,999,999 lines.
  1485.  */
  1486. void show_line_col( TDE_WIN *window )
  1487. {
  1488. int  i;
  1489. register int k;
  1490. char line_col[20], num[10];
  1491. char *hex_digit = "0123456789abcdef";
  1492.  
  1493.    /*
  1494.     * blank out current line:column position.
  1495.     */
  1496.    memset( line_col, ' ', 13 );
  1497.    line_col[13] = '\0';
  1498.  
  1499.    /*
  1500.     * convert column to ascii and store in display buffer.
  1501.     */
  1502.    my_ltoa( window->rcol+1, num, 10 );
  1503.    i = strlen( num ) - 1;
  1504.    for (k=12; i>=0; i--, k--)
  1505.       line_col[k] = num[i];
  1506.  
  1507.    /*
  1508.     * put in colon to separate line and column
  1509.     */
  1510.    line_col[k--] = ':';
  1511.  
  1512.    /*
  1513.     * convert line to ascii and store in display buffer.
  1514.     */
  1515.    my_ltoa( window->rline, num, 10 );
  1516.    i = strlen( num ) - 1;
  1517.    for (; i>=0; i--, k--)
  1518.       line_col[k] = num[i];
  1519.  
  1520.    /*
  1521.     * find line to start line:column display then output
  1522.     */
  1523.    s_output( line_col, window->top_line-1, window->end_col-12,
  1524.              g_display.head_color );
  1525.  
  1526.    strcpy( line_col, " =   " );
  1527.    i = window->rcol;
  1528.    if (g_status.copied) {
  1529.       if (mode.inflate_tabs)
  1530.          i = entab_adjust_rcol( (text_ptr)g_status.line_buff,
  1531.                                  g_status.line_buff_len, i );
  1532.       if (i < g_status.line_buff_len) {
  1533.          k = (unsigned char)g_status.line_buff[i];
  1534.          line_col[2] = *(hex_digit + (k >> 4));
  1535.          line_col[3] = *(hex_digit + (k & 0x000f));
  1536.          line_col[4] = 'x';
  1537.          i = TRUE;
  1538.       } else
  1539.          i = FALSE;
  1540.    } else {
  1541.       if (mode.inflate_tabs  &&  window->ll->len != EOF)
  1542.          i = entab_adjust_rcol( window->ll->line, window->ll->len, i );
  1543.       if (i < window->ll->len) {
  1544.          k = (int)window->ll->line[i];
  1545.          line_col[2] = *(hex_digit + (k >> 4));
  1546.          line_col[3] = *(hex_digit + (k & 0x000f));
  1547.          line_col[4] = 'x';
  1548.          i = TRUE;
  1549.       } else
  1550.          i = FALSE;
  1551.    }
  1552.    s_output( line_col, g_display.mode_line, 58, g_display.mode_color );
  1553.    if (i == TRUE)
  1554.       c_output( k, 58, g_display.mode_line, g_display.mode_color );
  1555.  
  1556.  
  1557.    /*
  1558.     * if file was opened in binary mode, show offset from beginning of file.
  1559.     */
  1560.    if (window->file_info->crlf == BINARY && !window->vertical) {
  1561.       k =  window->ll->line == NULL  ?  0  :  window->rcol;
  1562.       memset( line_col, ' ', 7 );
  1563.       line_col[7] = '\0';
  1564.       s_output( line_col, window->top_line-1, 61, g_display.head_color );
  1565.       my_ltoa( window->bin_offset + k, line_col, 10 );
  1566.       s_output( line_col, window->top_line-1, 61, g_display.head_color );
  1567.    }
  1568.    show_asterisk( window );
  1569. }
  1570.  
  1571.  
  1572. /*
  1573.  * Name:    show_asterisk
  1574.  * Purpose: give user an indication if file is dirty
  1575.  * Date:    September 16, 1991
  1576.  * Passed:  window:  pointer to current window
  1577.  */
  1578. void show_asterisk( TDE_WIN *window )
  1579. {
  1580.    c_output( window->file_info->modified ? '*' : ' ', window->start_col+4,
  1581.              window->top_line-1, g_display.head_color );
  1582. }
  1583.  
  1584.  
  1585. /*
  1586.  * Name:    toggle_overwrite
  1587.  * Purpose: toggle overwrite-insert mode
  1588.  * Date:    September 16, 1991
  1589.  * Passed:  arg_filler:  argument to satify function prototype
  1590.  */
  1591. int  toggle_overwrite( TDE_WIN *arg_filler )
  1592. {
  1593.    mode.insert = !mode.insert;
  1594.    show_insert_mode( );
  1595.    set_cursor_size( mode.insert ? g_display.insert_cursor :
  1596.                     g_display.overw_cursor );
  1597.    return( OK );
  1598. }
  1599.  
  1600.  
  1601. /*
  1602.  * Name:    toggle_smart_tabs
  1603.  * Purpose: toggle smart tab mode
  1604.  * Date:    June 5, 1992
  1605.  * Passed:  arg_filler:  argument to satify function prototype
  1606.  */
  1607. int  toggle_smart_tabs( TDE_WIN *arg_filler )
  1608. {
  1609.    mode.smart_tab = !mode.smart_tab;
  1610.    show_tab_modes( );
  1611.    return( OK );
  1612. }
  1613.  
  1614.  
  1615. /*
  1616.  * Name:    toggle_indent
  1617.  * Purpose: toggle indent mode
  1618.  * Date:    September 16, 1991
  1619.  * Passed:  arg_filler:  argument to satify function prototype
  1620.  */
  1621. int  toggle_indent( TDE_WIN *arg_filler )
  1622. {
  1623.    mode.indent = !mode.indent;
  1624.    show_indent_mode( );
  1625.    return( OK );
  1626. }
  1627.  
  1628.  
  1629. /*
  1630.  * Name:    set_left_margin
  1631.  * Purpose: set left margin for word wrap
  1632.  * Date:    November 27, 1991
  1633.  * Passed:  window
  1634.  */
  1635. int  set_left_margin( TDE_WIN *window )
  1636. {
  1637. register int rc;
  1638. char temp[MAX_COLS+2];
  1639.  
  1640.    my_ltoa( mode.left_margin + 1, temp, 10 );
  1641.    /*
  1642.     * enter left margin
  1643.     */
  1644.    rc = get_name( ed9, window->bottom_line, temp, g_display.message_color );
  1645.    if (rc == OK  &&  *temp != '\0') {
  1646.       rc = atoi( temp ) - 1;
  1647.       if (rc < 0 || rc >= mode.right_margin) {
  1648.          /*
  1649.           * left margin out of range
  1650.           */
  1651.          error( WARNING, window->bottom_line, ed10 );
  1652.          rc = ERROR;
  1653.       } else {
  1654.          mode.left_margin = rc;
  1655.          show_all_rulers( );
  1656.       }
  1657.    }
  1658.    return( rc );
  1659. }
  1660.  
  1661.  
  1662. /*
  1663.  * Name:    set_right_margin
  1664.  * Purpose: set right margin for word wrap
  1665.  * Date:    November 27, 1991
  1666.  * Passed:  window
  1667.  */
  1668. int  set_right_margin( TDE_WIN *window )
  1669. {
  1670. register int rc;
  1671. int  prompt_line;
  1672. char temp[MAX_COLS+2];
  1673. #if defined( __UNIX__ )
  1674.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  1675. #else
  1676.  char display_buff[(MAX_COLS+2)*2];
  1677. #endif
  1678.  
  1679.    prompt_line = window->bottom_line;
  1680.    save_screen_line( 0, prompt_line, display_buff );
  1681.    set_prompt( ed11a, prompt_line );
  1682.    rc = get_yn( );
  1683.    restore_screen_line( 0, prompt_line, display_buff );
  1684.    if (rc != ERROR) {
  1685.       mode.right_justify =  rc == A_YES ? TRUE : FALSE;
  1686.  
  1687.       my_ltoa( mode.right_margin + 1, temp, 10 );
  1688.       /*
  1689.        * enter right margin
  1690.        */
  1691.       rc = get_name( ed11, prompt_line, temp, g_display.message_color );
  1692.       if (rc == OK  &&  *temp != '\0') {
  1693.          rc = atoi( temp ) - 1;
  1694.          if (rc <= mode.left_margin || rc > MAX_LINE_LENGTH) {
  1695.             /*
  1696.              * right margin out of range
  1697.              */
  1698.             error( WARNING, prompt_line, ed12 );
  1699.             rc = ERROR;
  1700.          } else {
  1701.             mode.right_margin = rc;
  1702.             show_all_rulers( );
  1703.          }
  1704.       }
  1705.    }
  1706.    return( rc );
  1707. }
  1708.  
  1709.  
  1710. /*
  1711.  * Name:    set_paragraph_margin
  1712.  * Purpose: set column to begin paragraph
  1713.  * Date:    November 27, 1991
  1714.  * Passed:  window
  1715.  * Notes:   paragraph may be indented, flush, or offset.
  1716.  */
  1717. int  set_paragraph_margin( TDE_WIN *window )
  1718. {
  1719. register int rc;
  1720. char temp[MAX_COLS+2];
  1721.  
  1722.    my_ltoa( mode.parg_margin + 1, temp, 10 );
  1723.    /*
  1724.     * enter paragraph margin
  1725.     */
  1726.    rc = get_name( ed13, window->bottom_line, temp, g_display.message_color );
  1727.    if (rc == OK  &&  *temp != '\0') {
  1728.       rc = atoi( temp ) - 1;
  1729.       if (rc < 0 || rc >= mode.right_margin) {
  1730.          /*
  1731.           * paragraph margin out of range
  1732.           */
  1733.          error( WARNING, window->bottom_line, ed14 );
  1734.          rc = ERROR;
  1735.       } else {
  1736.          mode.parg_margin = rc;
  1737.          show_all_rulers( );
  1738.       }
  1739.    }
  1740.    return( rc );
  1741. }
  1742.  
  1743.  
  1744. /*
  1745.  * Name:    toggle_crlf
  1746.  * Purpose: toggle crlf mode
  1747.  * Date:    November 27, 1991
  1748.  * Passed:  arg_filler:  argument to satify function prototype
  1749.  */
  1750. int  toggle_crlf( TDE_WIN *window )
  1751. {
  1752. register TDE_WIN *w;
  1753.  
  1754.    ++window->file_info->crlf;
  1755.    if (window->file_info->crlf > BINARY)
  1756.       window->file_info->crlf = CRLF;
  1757.    w = g_status.window_list;
  1758.    while (w != NULL) {
  1759.       if (w->file_info == window->file_info  &&  w->visible)
  1760.          show_crlf_mode( w );
  1761.       w = w->next;
  1762.    }
  1763.    return( OK );
  1764. }
  1765.  
  1766.  
  1767. /*
  1768.  * Name:    toggle_ww
  1769.  * Purpose: toggle word wrap mode
  1770.  * Date:    November 27, 1991
  1771.  * Passed:  arg_filler:  argument to satify function prototype
  1772.  */
  1773. int  toggle_ww( TDE_WIN *arg_filler )
  1774. {
  1775.    ++mode.word_wrap;
  1776.    if (mode.word_wrap > DYNAMIC_WRAP)
  1777.       mode.word_wrap = NO_WRAP;
  1778.    show_wordwrap_mode( );
  1779.    return( OK );
  1780. }
  1781.  
  1782.  
  1783. /*
  1784.  * Name:    toggle_trailing
  1785.  * Purpose: toggle eleminating trainling space at eol
  1786.  * Date:    November 25, 1991
  1787.  * Passed:  arg_filler:  argument to satify function prototype
  1788.  */
  1789. int  toggle_trailing( TDE_WIN *arg_filler )
  1790. {
  1791.    mode.trailing = !mode.trailing;
  1792.    show_trailing( );
  1793.    return( OK );
  1794. }
  1795.  
  1796.  
  1797. /*
  1798.  * Name:    toggle_z
  1799.  * Purpose: toggle writing control z at eof
  1800.  * Date:    November 25, 1991
  1801.  * Passed:  arg_filler:  argument to satify function prototype
  1802.  */
  1803. int  toggle_z( TDE_WIN *arg_filler )
  1804. {
  1805.    mode.control_z = !mode.control_z;
  1806.    show_control_z( );
  1807.    return( OK );
  1808. }
  1809.  
  1810.  
  1811. /*
  1812.  * Name:    toggle_eol
  1813.  * Purpose: toggle writing eol character at eol
  1814.  * Date:    November 25, 1991
  1815.  * Passed:  arg_filler:  argument to satify function prototype
  1816.  */
  1817. int  toggle_eol( TDE_WIN *arg_filler )
  1818. {
  1819. register file_infos *file;
  1820.  
  1821.    mode.show_eol = !mode.show_eol;
  1822.    for (file=g_status.file_list; file != NULL; file=file->next)
  1823.       file->dirty = GLOBAL;
  1824.    return( OK );
  1825. }
  1826.  
  1827.  
  1828. /*
  1829.  * Name:    toggle_search_case
  1830.  * Purpose: toggle search case
  1831.  * Date:    September 16, 1991
  1832.  * Passed:  arg_filler:  argument to satify function prototype
  1833.  */
  1834. int  toggle_search_case( TDE_WIN *arg_filler )
  1835. {
  1836.    mode.search_case = (mode.search_case == IGNORE) ? MATCH : IGNORE;
  1837.    show_search_case( );
  1838.    build_boyer_array( );
  1839.    return( OK );
  1840. }
  1841.  
  1842.  
  1843. /*
  1844.  * Name:    toggle_sync
  1845.  * Purpose: toggle sync mode
  1846.  * Date:    January 15, 1992
  1847.  * Passed:  arg_filler:  argument to satify function prototype
  1848.  */
  1849. int  toggle_sync( TDE_WIN *arg_filler )
  1850. {
  1851.    mode.sync = !mode.sync;
  1852.    show_sync_mode( );
  1853.    return( OK );
  1854. }
  1855.  
  1856.  
  1857. /*
  1858.  * Name:    toggle_ruler
  1859.  * Purpose: toggle ruler
  1860.  * Date:    March 5, 1992
  1861.  * Passed:  arg_filler:  argument to satify function prototype
  1862.  */
  1863. int  toggle_ruler( TDE_WIN *arg_filler )
  1864. {
  1865. register TDE_WIN *wp;
  1866.  
  1867.    mode.ruler = !mode.ruler;
  1868.    wp = g_status.window_list;
  1869.    while (wp != NULL) {
  1870.       if (mode.ruler) {
  1871.          /*
  1872.           * there has to be more than one line in a window to display a ruler.
  1873.           *   even if the ruler mode is on, we need to check the num of lines.
  1874.           */
  1875.          if (wp->bottom_line - wp->top_line >0) {
  1876.             if (wp->cline == wp->top_line)
  1877.                ++wp->cline;
  1878.             if (wp->cline > wp->bottom_line)
  1879.                wp->cline = wp->bottom_line;
  1880.             wp->ruler = TRUE;
  1881.          } else
  1882.             wp->ruler = FALSE;
  1883.       } else {
  1884.  
  1885.          /*
  1886.           * if this is the first page in a file, then we may need to "pull"
  1887.           *   the file up before displaying the first page.
  1888.           */
  1889.          if (wp->rline == ((wp->cline - wp->ruler) - (wp->top_line - 1)))
  1890.             --wp->cline;
  1891.          if (wp->cline < wp->top_line)
  1892.             wp->cline = wp->top_line;
  1893.          wp->ruler = FALSE;
  1894.       }
  1895.       make_ruler( wp );
  1896.       setup_window( wp );
  1897.       if (wp->visible)
  1898.          redraw_current_window( wp );
  1899.       wp = wp->next;
  1900.    }
  1901.    return( OK );
  1902. }
  1903.  
  1904.  
  1905. /*
  1906.  * Name:    toggle_tabinflate
  1907.  * Purpose: toggle inflating tabs
  1908.  * Date:    October 31, 1992
  1909.  * Passed:  arg_filler:  argument to satify function prototype
  1910.  */
  1911. int  toggle_tabinflate( TDE_WIN *arg_filler )
  1912. {
  1913. register file_infos *file;
  1914.  
  1915.    mode.inflate_tabs = !mode.inflate_tabs;
  1916.    for (file=g_status.file_list; file != NULL; file=file->next)
  1917.       file->dirty = GLOBAL;
  1918.    show_tab_modes( );
  1919.    return( OK );
  1920. }
  1921.  
  1922.  
  1923. /*
  1924.  * Name:    cursor_sync
  1925.  * Purpose: carry out cursor movements in all visible windows
  1926.  * Date:    January 15, 1992
  1927.  * Passed:  window
  1928.  * Notes:   switch sync semaphore when we do this so we don't get into a
  1929.  *          recursive loop.  all cursor movement commands un_copy_line before
  1930.  *          moving the cursor off the current line.   you MUST make certain
  1931.  *          that the current line is uncopied in the task routines that
  1932.  *          move the cursor off the current line before calling sync.
  1933.  */
  1934. void cursor_sync( TDE_WIN *window )
  1935. {
  1936. register TDE_WIN *wp;
  1937. register file_infos *fp;
  1938.  
  1939.    if (mode.sync && mode.sync_sem) {
  1940.  
  1941.    /*
  1942.     * these functions must un_copy a line before sync'ing
  1943.     */
  1944. #if defined( __MSC__ )
  1945.       switch (g_status.command) {
  1946.          case  NextLine        :
  1947.          case  BegNextLine     :
  1948.          case  LineDown        :
  1949.          case  LineUp          :
  1950.          case  WordRight       :
  1951.          case  WordLeft        :
  1952.          case  ScreenDown      :
  1953.          case  ScreenUp        :
  1954.          case  EndOfFile       :
  1955.          case  TopOfFile       :
  1956.          case  BotOfScreen     :
  1957.          case  TopOfScreen     :
  1958.          case  JumpToLine      :
  1959.          case  CenterWindow    :
  1960.          case  CenterLine      :
  1961.          case  ScrollDnLine    :
  1962.          case  ScrollUpLine    :
  1963.          case  PanUp           :
  1964.          case  PanDn           :
  1965.          case  NextDirtyLine   :
  1966.          case  PrevDirtyLine   :
  1967.          case  ParenBalance    :
  1968.             assert( g_status.copied == FALSE );
  1969.             break;
  1970.          default  :
  1971.             break;
  1972.       }
  1973. #endif
  1974.  
  1975.       mode.sync_sem = FALSE;
  1976.       for (wp = g_status.window_list;  wp != NULL;  wp = wp->next) {
  1977.          if (wp->visible  &&  wp != window) {
  1978.  
  1979.             /*
  1980.              * when we sync a command, we need to use the same assertions
  1981.              *  as those in editor( ).
  1982.              *
  1983.              * if everything is everything, these core asserts are TRUE.
  1984.              */
  1985. #if defined( __MSC__ )
  1986.             assert( wp != NULL );
  1987.             assert( wp->file_info != NULL );
  1988.             assert( wp->file_info->line_list != NULL );
  1989.             assert( wp->file_info->line_list_end != NULL );
  1990.             assert( wp->file_info->line_list_end->len == EOF );
  1991.             assert( wp->visible == TRUE );
  1992.             assert( wp->rline >= 0 );
  1993.             assert( wp->rline <= wp->file_info->length + 1 );
  1994.             assert( wp->rcol >= 0 );
  1995.             assert( wp->rcol < MAX_LINE_LENGTH );
  1996.             assert( wp->ccol >= wp->start_col );
  1997.             assert( wp->ccol <= wp->end_col );
  1998.             assert( wp->bcol >= 0 );
  1999.             assert( wp->bcol < MAX_LINE_LENGTH );
  2000.             assert( wp->bcol == wp->rcol-(wp->ccol - wp->start_col) );
  2001.             assert( wp->start_col >= 0 );
  2002.             assert( wp->start_col < wp->end_col );
  2003.             assert( wp->end_col < g_display.ncols );
  2004.             assert( wp->cline >= wp->top_line );
  2005.             assert( wp->cline <= wp->bottom_line );
  2006.             assert( wp->top_line > 0 );
  2007.             assert( wp->top_line <= wp->bottom_line );
  2008.             assert( wp->bottom_line <= g_display.nlines );
  2009.             assert( wp->bin_offset >= 0 );
  2010.             if (wp->ll->next == NULL)
  2011.                assert( wp->ll->len == EOF );
  2012.             else
  2013.                assert( wp->ll->len >= 0 );
  2014.             assert( wp->ll->len <  MAX_LINE_LENGTH );
  2015. #endif
  2016.  
  2017.             (*do_it[g_status.command])( wp );
  2018.             show_line_col( wp );
  2019.             show_ruler_pointer( wp );
  2020.          }
  2021.       }
  2022.       mode.sync_sem = TRUE;
  2023.       for (fp = g_status.file_list; fp != NULL; fp = fp->next)
  2024.          if (fp->dirty != FALSE)
  2025.             fp->dirty = GLOBAL;
  2026.    }
  2027. }
  2028.  
  2029.  
  2030. /*
  2031.  * Name:    editor
  2032.  * Purpose: Set up the editor structures and display changes as needed.
  2033.  * Date:    June 5, 1991
  2034.  * Notes:   Master editor routine.
  2035.  */
  2036. void editor( )
  2037. {
  2038. char *name;  /* name of file to start editing */
  2039. register TDE_WIN *window;        /* current active window */
  2040. int  c;
  2041. #if defined( __UNIX__ )
  2042.    mode_t fattr;
  2043. #endif
  2044.  
  2045.    /*
  2046.     * initialize search and seize
  2047.     */
  2048.    g_status.sas_defined = FALSE;
  2049.    for (c=0; c<SAS_P; c++)
  2050.       g_status.sas_arg_pointers[c] = NULL;
  2051.  
  2052.    g_status.file_mode = TEXT;
  2053.    /*
  2054.     * Check that user specified file to edit, if not offer help
  2055.     */
  2056.    if (g_status.argc > 1) {
  2057.       c = *g_status.argv[1];
  2058.  
  2059. #if defined( __UNIX__ )
  2060.       if (c == '-'  ||  c == '+')
  2061. #else
  2062.       if (c == '/'  ||  c == '-'  ||  c == '+')
  2063. #endif
  2064.       {
  2065.          c = *(g_status.argv[1] + 1);
  2066.          if (c == 'f' || c == 'F' || c == 'g' || c == 'G') {
  2067.             /*
  2068.              * with search and seize their has to be at least 4 arg's, e.g.
  2069.              *    tde -f findme *.c
  2070.              */
  2071.             if (c == 'F' || c == 'G') {
  2072.                mode.search_case = MATCH;
  2073.                c = bj_tolower( c );
  2074.             }
  2075.  
  2076.             if (g_status.argc >= 4) {
  2077.  
  2078.                assert( strlen( g_status.argv[2] ) < (size_t)g_display.ncols );
  2079.  
  2080.                if (c == 'f') {
  2081.                   g_status.command = DefineGrep;
  2082.                   strcpy( (char *)sas_bm.pattern, g_status.argv[2] );
  2083.                } else {
  2084.                   g_status.command = DefineRegXGrep;
  2085.                   strcpy( (char *)regx.pattern, g_status.argv[2] );
  2086.                }
  2087.  
  2088. #if defined( __UNIX__ )
  2089.                g_status.sas_argc = g_status.argc - 3;
  2090.                g_status.sas_arg = 0;
  2091.                g_status.sas_argv = g_status.argv + 3;
  2092. #else
  2093.                for (c=3; c <= g_status.argc; c++)
  2094.                   g_status.sas_arg_pointers[c-3] = g_status.argv[c];
  2095.                g_status.sas_argc = g_status.argc - 3;
  2096.                g_status.sas_arg = 0;
  2097.                g_status.sas_argv = g_status.sas_arg_pointers;
  2098. #endif
  2099.                g_status.sas_found_first = FALSE;
  2100.                if (g_status.command == DefineGrep) {
  2101.                   g_status.sas_defined = TRUE;
  2102.                   g_status.sas_search_type = BOYER_MOORE;
  2103.                   bm.search_defined = sas_bm.search_defined = OK;
  2104.                   build_boyer_array( );
  2105.                   c = OK;
  2106.                } else {
  2107.                   c = build_nfa( );
  2108.                   if (c == OK) {
  2109.                      g_status.sas_defined = TRUE;
  2110.                      g_status.sas_search_type = REG_EXPRESSION;
  2111.                      regx.search_defined = sas_regx.search_defined = OK;
  2112.                   } else
  2113.                      g_status.sas_defined = FALSE;
  2114.                }
  2115.                if (c != ERROR)
  2116.                   c = search_and_seize( g_status.current_window );
  2117.             } else
  2118.                c = ERROR;
  2119.          } else if (c == 'b' || c == 'B') {
  2120.             c = atoi( g_status.argv[1] + 2 );
  2121.             if (c <= 0 || c >= MAX_LINE_LENGTH)
  2122.                c = DEFAULT_BIN_LENGTH;
  2123.             ++g_status.arg;
  2124.             g_status.file_mode = BINARY;
  2125.             g_status.file_chunk = c;
  2126.             c = edit_next_file( g_status.current_window );
  2127.          } else if (c >= '0' && c <= '9') {
  2128.             c = atoi( g_status.argv[1] + 1 );
  2129.             g_status.jump_to = c;
  2130.             ++g_status.arg;
  2131.             c = edit_next_file( g_status.current_window );
  2132.          } else
  2133.             c = ERROR;
  2134.       } else
  2135.          c = edit_next_file( g_status.current_window );
  2136.    } else {
  2137.       name = g_status.rw_name;
  2138.       *name = '\0';
  2139.       /*
  2140.        * file name to edit
  2141.        */
  2142.       c = get_name( ed15, g_display.nlines, name, g_display.text_color );
  2143.  
  2144.       assert( strlen( name ) < (size_t)g_display.ncols );
  2145.  
  2146.       if (c == OK) {
  2147.          if (*name != '\0') {
  2148. #if defined( __UNIX__ )
  2149.             if (get_fattr( name, &fattr) == 0)
  2150. #else
  2151.             if (get_fattr( name, &c) == 0)
  2152. #endif
  2153.                c = attempt_edit_display( name, GLOBAL, TEXT, 0 );
  2154.             else
  2155.                c = dir_help_name( (TDE_WIN *)NULL, name );
  2156.          } else
  2157.             c = dir_help( (TDE_WIN *)NULL );
  2158.       }
  2159.    }
  2160.  
  2161.    g_status.stop =   c == OK  ?  FALSE  :  TRUE;
  2162.    if (c == OK)
  2163.       set_cursor_size( mode.insert ? g_display.insert_cursor :
  2164.                        g_display.overw_cursor );
  2165.  
  2166.    /*
  2167.     * main loop - keep updating the display and processing any commands
  2168.     *  while user has not pressed the stop key
  2169.     */
  2170.    for (; g_status.stop != TRUE;) {
  2171.       window = g_status.current_window;
  2172.  
  2173.  
  2174.       /*
  2175.        * before we do any editor commands, we start out with some basic
  2176.        *   assumptions.
  2177.        *
  2178.        * if everything is everything, these core asserts are TRUE.
  2179.        */
  2180.       assert( window != NULL );
  2181.       assert( window->file_info != NULL );
  2182.       assert( window->file_info->line_list != NULL );
  2183.       assert( window->file_info->line_list_end != NULL );
  2184.       assert( window->file_info->line_list_end->len == EOF );
  2185.       assert( window->visible == TRUE );
  2186.       assert( window->rline >= 0 );
  2187.       assert( window->rline <= window->file_info->length + 1 );
  2188.       assert( window->rcol >= 0 );
  2189.       assert( window->rcol < MAX_LINE_LENGTH );
  2190.       assert( window->ccol >= window->start_col );
  2191.       assert( window->ccol <= window->end_col );
  2192.       assert( window->bcol >= 0 );
  2193.       assert( window->bcol < MAX_LINE_LENGTH );
  2194.       assert( window->bcol == window->rcol-(window->ccol - window->start_col) );
  2195.       assert( window->start_col >= 0 );
  2196.       assert( window->start_col < window->end_col );
  2197.       assert( window->end_col < g_display.ncols );
  2198.       assert( window->cline >= window->top_line );
  2199.       assert( window->cline <= window->bottom_line );
  2200.       assert( window->top_line > 0 );
  2201.       assert( window->top_line <= window->bottom_line );
  2202.       assert( window->bottom_line <= g_display.nlines );
  2203.       assert( window->bin_offset >= 0 );
  2204.       if (window->ll->next == NULL)
  2205.          assert( window->ll->len == EOF );
  2206.       else
  2207.          assert( window->ll->len >= 0 );
  2208.       assert( window->ll->len <  MAX_LINE_LENGTH );
  2209.  
  2210.       display_dirty_windows( window );
  2211.  
  2212.       /*
  2213.        * set the critical error handler flag to a known state before we
  2214.        *   do each editor command.
  2215.        */
  2216.       ceh.flag = OK;
  2217.  
  2218. /*
  2219.  * this code is used during testing to check the amount of memory
  2220.  *    in the near heap.
  2221.  *
  2222.  *  ultoa( _fmsize( window->ll ), buff, 10 );
  2223.  *  s_output( "s=       ", g_display.mode_line, 15, g_display.mode_color );
  2224.  *  s_output( buff, g_display.mode_line, 17, g_display.mode_color );
  2225.  */
  2226.  
  2227.       /*
  2228.        * Get a key from the user.  Look up the function assigned to that key.
  2229.        * All regular text keys are assigned to function 0.  Text characters
  2230.        * are less than 0x100, decimal 256, which includes the ASCII and
  2231.        * extended ASCII character set.
  2232.        */
  2233. #if defined( __UNIX__ )
  2234.       xygoto( window->ccol, window->cline );
  2235.       refresh( );
  2236. #endif
  2237.  
  2238.       g_status.key_pressed = getkey( );
  2239.       g_status.command = getfunc( g_status.key_pressed );
  2240.       if (g_status.wrapped  ||  g_status.key_pending) {
  2241.          g_status.key_pending = FALSE;
  2242.          g_status.wrapped = FALSE;
  2243.          show_search_message( CLR_SEARCH, g_display.mode_color );
  2244.       }
  2245.       g_status.control_break = FALSE;
  2246.       if (g_status.command >= 0 && g_status.command < NUM_FUNCS) {
  2247.          record_keys( window->bottom_line );
  2248.          (*do_it[g_status.command])( window );
  2249.       }
  2250.    }
  2251.  
  2252.  
  2253. #if defined( __UNIX__ )
  2254.    curs_set( CURSES_SMALL );
  2255.    refresh( );
  2256. #else
  2257.    cls( );
  2258.    xygoto( 0, 0 );
  2259. #endif
  2260.  
  2261. }
  2262.  
  2263.  
  2264. /*
  2265.  * Name:    display_dirty_windows
  2266.  * Purpose: Set up the editor structures and display changes as needed.
  2267.  * Date:    June 5, 1991
  2268.  * Notes:   Display all windows with dirty files.
  2269.  */
  2270. void display_dirty_windows( TDE_WIN *window )
  2271. {
  2272. register TDE_WIN *below;         /* window below current */
  2273. register TDE_WIN *above;         /* window above current */
  2274. file_infos *file;               /* temporary file structure */
  2275.  
  2276.    /*
  2277.     * update all windows that point to any file that has been changed
  2278.     */
  2279.    above = below = window;
  2280.    while (above->prev || below->next) {
  2281.       if (above->prev) {
  2282.          above = above->prev;
  2283.          show_dirty_window( above );
  2284.       }
  2285.       if (below->next) {
  2286.          below = below->next;
  2287.          show_dirty_window( below );
  2288.       }
  2289.    }
  2290.    file = window->file_info;
  2291.    if (file->dirty == LOCAL || file->dirty == GLOBAL)
  2292.       display_current_window( window );
  2293.    for (file=g_status.file_list; file != NULL; file=file->next)
  2294.       file->dirty = FALSE;
  2295.  
  2296.    /*
  2297.     * Set the cursor position at window->ccol, window->cline.  Show the
  2298.     * user where in the file the cursor is positioned.
  2299.     */
  2300.    xygoto( window->ccol, window->cline );
  2301.    show_line_col( window );
  2302.    show_ruler_pointer( window );
  2303. }
  2304.  
  2305.  
  2306.  
  2307. /*
  2308.  * Name:    show_dirty_window
  2309.  * Purpose: show changes in non-current window
  2310.  * Date:    June 5, 1991
  2311.  * Passed:  window:  pointer to current window
  2312.  */
  2313. void show_dirty_window( TDE_WIN *window )
  2314. {
  2315. register TDE_WIN *win;   /* register window pointer */
  2316. int  dirty;
  2317.  
  2318.   win = window;
  2319.   if (win->visible) {
  2320.      dirty = win->file_info->dirty;
  2321.      if (dirty == GLOBAL || dirty == NOT_LOCAL) {
  2322.         display_current_window( win );
  2323.         show_size( win );
  2324.      }
  2325.      show_asterisk( win );
  2326.   }
  2327. }
  2328.